翻译 - 数据路径配置
本文翻译自 Eclipse Cyclone DDS 11.0.0 官方文档 Data path configuration,内容涵盖:重传合并与重传积压控制、样本分片策略、接收线程模型、最小化接收延迟与最大样本大小。适合需要调优 CycloneDDS 数据吞吐或排查收发路径问题的读者。译文忠实原文,配置项名称保留英文原样。
重传合并
当远程读取者(Reader)接收到心跳包并检测到样本丢失时,可以请求重传。如果某个样本在网络中丢失,导致多个甚至所有读取者都无法接收,下一次心跳可能会触发大量的重传请求。因此,为了避免向众多不同的读取者反复重传同一个样本,写入器(Writer)应尝试将这些请求合并为一次多播重传。同样,虽然读取者应尽量避免过于频繁地请求重传,但在一个可互操作的系统中,写入器必须具备处理这种情况的健壮性。
当接收到指示样本丢失的心跳包时,读取者会执行以下操作之一:
- 将第二次及后续的重传请求调度为延迟发送(延迟时间由
Internal/NackDelay设置)。 - 将其与已调度的请求合并。在接收到心跳包到发送
AckNack之间收到的任何样本都不需要重传。
写入器尝试合并重传请求的方式如下:
- 当另一个重传请求到达,且之前的重传尚未发生时,将消息从单播改为多播。这在因带宽限制导致待重传样本积压时尤为有效。
- 合并重传请求:通过
Internal/ReTransmitMerging配置。
重传积压
读取者可以一次性请求重传大量样本。当写入器将所有这些样本排队等待重传时,可能会导致大量的样本积压。结果是,队列末端的样本可能会被延迟太久,以至于读取者再次发出重传请求。
Eclipse Cyclone DDS 限制了排队等待重传的样本数量,并忽略那些会导致重传队列包含过多样本或处理时间过长的重传请求。两个设置控制了这些队列的大小。限制是按定时事件线程(timed-event thread)应用的:
- 重传消息的数量:
Internal/MaxQueuedRexmitMessages。 - 队列大小:
Internal/MaxQueuedRexmitBytes。默认值基于允许传输带宽与Internal/NackDelay设置的组合,后者是对读取者下一次重传请求时间的近似估算。
分片 (Fragmentation)
DDS 中的样本大小可以是任意的,并不总能容纳在单个数据报中。DDSI 可以对样本进行分片,使其适应 UDP 数据报。IP 层具备将 UDP 数据报分片为网络数据包的能力。DDSI 规范(参见 DDSI-RTPS 2.5 第 8.4.14.1.2 节)描述了如何发送分片(仅在必要时对数据进行分片)。然而,Eclipse Cyclone DDS 提供了完全可配置的行为。
如果样本的序列化形式大小达到 General/FragmentSize 设定的值,则使用 DDSI 分片机制对其进行分片。所有分片的大小均为此确切值,最后一个分片除外(可能较小)。
为了减少网络数据包的数量,以下内容在发送到网络之前,会根据各种属性(如目标地址)打包到数据报中:
- 控制消息
- 未分片的样本
- 样本分片
打包允许数据报负载最大达到 General/MaxMessageSize。如果 MaxMessageSize 太小而无法将整个数据报负载作为一个单元容纳……
注意
最大消息大小计算中未包含 UDP/IP 头部的大小。
为了保持在底层网络支持的最大尺寸以内,IP 层会将数据报分片为多个数据包。
这里存在一个权衡:虽然 DDSI 分片可以单独重传,但 DDSI 分片的处理开销大于 UDP 分片。
接收处理
数据接收被分配到多个线程中:
一个单一的接收线程,负责:
- 检索所有传入的网络数据包。
- 运行协议状态机,涉及
AckNack和心跳消息的调度。 - 对待重传的样本进行排队。
- 重组分片(Defragmenting)。
- 对传入样本进行排序。
在接收线程和交付线程之间存在队列。要控制最大队列大小,请设置 Internal/DeliveryQueueMaxSamples。通常,队列不需要非常大(除非是在非常大的消息中包含非常小的样本)。其主要功能是在成批样本同时可用时(例如重传后)平滑处理过程。
当任何接收缓冲区达到其大小限制,且涉及应用数据时,接收线程会等待队列缩小。然而,发现数据(discovery data)永远不会阻塞接收线程。
一个专用于处理 DDSI 内置数据的交付线程:
- 参与者发现
- 端点发现
- 活跃性断言
一个或多个专用于处理应用数据的交付线程:
- 反序列化
- 交付至 DCPS 数据读取者缓存
分片数据首先进入每个代理写入器(proxy writer)独立的重组阶段。可同时重组的样本数量受到限制:
- 可靠数据:
Internal/DefragReliableMaxSamples - 不可靠数据:
Internal/DefragUnreliableMaxSamples
乱序接收的样本(如有必要先进行重组)会被缓冲:
- 最初按每个代理写入器缓冲。大小限制为:
Internal/PrimaryReorderMaxSamples。 - 然后按每个读取者缓冲(用于追赶历史性的瞬态本地数据)。大小限制为:
Internal/SecondaryReorderMaxSamples。
最小化接收延迟
在低延迟环境中,通过以下方式处理应用数据可以节省几微秒:
- 直接在接收线程中处理。
- 相对于传入的网络流量同步处理(而不是将其排队供交付线程异步处理)。
这适用于 max_latency QoS 设置为可配置值,且 transport_priority QoS 也设置为可配置值的数据传输。默认情况下,这些值分别为无穷大(inf)和最大传输优先级,从而有效地为所有数据启用同步交付。
最大样本大小
要控制服务可处理的样本最大大小,请设置 Internal/MaxSampleSize。该大小指通用数据表示(CDR)序列化负载的大小,此限制对内置数据和应用数据均适用。
注意
(CDR) 序列化负载的大小永远不会超过数据的内存表示形式。
发送时:大于 Internal/MaxSampleSize 的样本将被丢弃并产生警告。Eclipse Cyclone DDS 的表现仿佛该样本从未存在过。
由于发送方完全忽略了该样本,接收方会假设样本已正确接收并向写入器确认收到,从而使通信得以继续。
接收时:大于 Internal/MaxSampleSize 的样本会尽早被丢弃。为了防止资源被占用超过严格必要的时间,样本会在接收到该样本或其某个分片后立即被丢弃。
注意
当接收方丢弃样本时,读取者会在下一个交付的样本中收到一个"样本丢失"通知。此通知很容易被忽略。因此,确定样本是否被丢弃的唯一可靠方法是检查日志。
虽然尽早丢弃样本(或其分片)有利于减少资源使用,但这使得判断特定样本的丢弃是否已被记录到日志中变得困难。在正常操作情况下,每个被丢弃的样本仅记录一条消息,但偶尔也会报告同一样本的多个事件。
可以将 Internal/MaxSampleSize 设置为非常小的值(甚至小到无法通信发现数据),但这不推荐。
相关阅读:发现与代理机制见《翻译 - CycloneDDS 发现行为》及《Cyclone DDS 代理模型:发现协议与状态镜像》。